home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 …ember: Reference Library / Dev.CD Dec 00 RL Disk 1.toast / pc / technical documentation / develop / develop issue 26 / develop issue 26 code / wide (64 bit) library / sources / wide.c < prev   
Encoding:
C/C++ Source or Header  |  1996-08-05  |  34.7 KB  |  1,473 lines

  1. /**********************************************************
  2.  
  3.     Wide.c
  4.  
  5.     Author:
  6.         Dale Semchishen, 1996
  7.         Modified by Terry Teague for MPW
  8.  
  9.     Description:
  10.         A 64 bit integer library for the 680x0 and PowerPC processors
  11.  
  12.         While this library is self-initializing you can choose
  13.         to call WideInit() during application startup so that
  14.         the first time you call a math routine it does not incur
  15.         the extra time required for initialization.
  16.  
  17.         Most of the 64 bit routines in this library are available in
  18.         QuickDraw GX or on the PowerPC. On the 680x0 if you include
  19.         <GXTypes.h> or <GXMath.h> before "Wide.h" and compile this library,
  20.         the QuickDraw GX traps will be used instead of the routines
  21.         marked with "(gx)".
  22.  
  23.  
  24.     Global functions:
  25.         WideInit()            - Initialize the Wide library (optional)
  26.  
  27.         WideAdd()              - (gx) Add two 64 bit ints
  28.         WideAdd32()            -      Add 32 bits to a 64 bit int
  29.         WideAssign32()        -      Assign 32 bits to 64 bit int
  30.         WideBitShift()        -      Shift a 64 bit number
  31.         WideCompare()        - (gx) Compare two 64 bits ints
  32.         WideDivide()        - (gx) Divide 32 bit int into 64 bit int with a 32 bit result
  33.         WideMultiply()        - (gx) Multiply two 32 bits ints for a 64 bit result
  34.         WideNegate()        - (gx) Negative value of a 64 bit int
  35.         WideScale()            - (gx) Highest order nonzero bit in a 64 bit number
  36.         WideShift()            - (gx) Shift a 64 bit number and round up
  37.         WideSquareRoot()    - (gx) return 32 bit square root of an unsigned 64 bit number
  38.         WideSubtract32()    -      Subtract 32 bits from a 64 bit int
  39.         WideSubtract()        - (gx) Subtract a 64 bits int from a 64 bit int
  40.         WideToDecStr()        -      Convert 64 bit int to a SANE 'decimal' string
  41.         WideWideDivide()    - (gx) Divide 32 bit int into 64 bit int with a 64 bit result
  42.  
  43.     Note:
  44.          This library has been compiled under the following
  45.          development systems:
  46.              - Symantec C 68K 7.0.4
  47.              - CodeWarrior 6 Lite (68K and PPC)
  48.              - CodeWarrior 9 (68K and PPC) - Terry Teague
  49.             - MPW 3.3.1 (MPWC 68K and PPCC PPC) - Terry Teague
  50.             - MPW 3.4.1 (SC 68K and MrC PPC) - Terry Teague
  51.  
  52.  **********************************************************/
  53.  
  54.  
  55. #include "Wide.h"
  56.  
  57. #include <ToolUtils.h>
  58. #if    !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300)
  59. #include <GestaltEqu.h>
  60. #else
  61. #include <Gestalt.h>
  62. #endif
  63.  
  64.  
  65. /*------------------- Local Constants --------------------*/
  66.  
  67. #define LONG_SIGN_BIT 0x80000000
  68.  
  69.  
  70. /*------------------- Local Variables --------------------*/
  71.  
  72. /* Is the Wide math library initialized ? */
  73. static short gWide_Initialized = false;
  74.  
  75. /* Are the MC680x0 64 bit multiply and divide instructions available ? */
  76. static short gWide_64instr = false;
  77.  
  78.  
  79. /*---------------- Compiler Dependencies -----------------*/
  80.  
  81. #ifdef    NEED_EXTENDED80
  82. /* not defined in Types.h for Universal Headers version 1.0 */
  83. /* or pre-Universal Headers */
  84. struct _extended80 {
  85.     short                    exp;
  86.     short                    man[4];
  87. };
  88. #endif
  89.  
  90. /* IF generating code for 680x0 CPUs */
  91. #if GENERATING68K
  92.  
  93. /* IF MetroWorks compiler */
  94. #ifdef __MWERKS__
  95.  
  96. typedef extended80   Extended_80;
  97. typedef DecForm      decform;
  98. #define FIXEDDECIMAL FixedDecimal
  99.  
  100. #define ASM_FUNC_HEAD    asm
  101. #define ASM_BEGIN        LINK A6,#0
  102. #define ASM_END            UNLK A6
  103. #define ASM_FUNC_TAIL     RTS
  104.  
  105. #define WIDE_HI 0
  106. #define WIDE_LO 4
  107.  
  108. /* ELSE IF Symantec C */
  109. #elif THINK_C
  110.  
  111. typedef extended    Extended_80;
  112.  
  113. #define ASM_FUNC_HEAD
  114. #define ASM_BEGIN        asm{
  115. #define ASM_END            }
  116. #define ASM_FUNC_TAIL
  117.  
  118. #define WIDE_LO wide.lo
  119. #define WIDE_HI wide.hi
  120.  
  121. /* ELSE IF MPW C */
  122. #elif defined(MPWC)
  123.  
  124. typedef extended80   Extended_80;
  125.  
  126. /* MPW 68K assembly language code in Wide.a */
  127.  
  128. #else
  129. #error "Wide library has not been ported to this 68K environment"
  130. #endif
  131.  
  132. /* ELSE generating code for PowerPC */
  133. #else
  134.  
  135. /* IF the MetroWorks compiler */
  136. #ifdef __MWERKS__
  137.  
  138. typedef struct _extended80  Extended_80;
  139.  
  140. /* ELSE IF MPW PPCC */
  141. #elif defined(PPCC)
  142.  
  143. typedef struct _extended80  Extended_80;
  144.  
  145. /* ELSE IF Symantec C */
  146. #elif defined(__SC__)
  147.  
  148. /* ELSE IF MrC */
  149. #elif defined(__MrC__)
  150.  
  151. #else
  152. #error "Wide library has not been ported to this PowerPC environment"
  153. #endif
  154.  
  155. #endif
  156.  
  157.  
  158.  
  159. /**********************************************************
  160.  
  161.     WideInit - Initialize the Wide math library
  162.  
  163.     Description:
  164.         This routine will set the internal flags used by the
  165.         Wide math library. These flags tested by the multiply
  166.         and divide functions in order to determine if there
  167.         are 680x0 64 bit math instructions that can be used
  168.         instead of a software algorithm.
  169.  
  170.         While this library is self-initializing you can choose
  171.         to call WideInit() during application startup so that
  172.         the first time you call a math routine it does not incur
  173.         the extra time required for initialization.
  174.  
  175.     Return value:
  176.         none
  177.  
  178. **********************************************************/
  179. void WideInit( void )
  180. {
  181.     long   processor_type;
  182.     
  183.  
  184.     /* IF able to determine processor type */
  185.     if( Gestalt( gestaltProcessorType, &processor_type ) == noErr )
  186.     {
  187.         processor_type &= 0xFFFF;
  188.     }
  189.     /* ELSE assume we have the oldest CPU */
  190.     else
  191.     {
  192.         processor_type = gestalt68000;
  193.     }
  194.  
  195.     /* 64 bit mult and div instructions available if CPU is 68020 to 68040 */
  196.     gWide_64instr = (processor_type >= gestalt68020) &&
  197.                     (processor_type <= gestalt68040);
  198.  
  199.     gWide_Initialized = true;
  200. }
  201.  
  202.  
  203.  
  204. /**********************************************************
  205.  
  206.     WideAssign32 - Assign 32 bits to 64 bit int
  207.  
  208.     Description:
  209.         This routine will assign a signed 32 bit integer to
  210.         a signed 64 bit integer
  211.  
  212.     Return value:
  213.         the target pointer passed into this function
  214.  
  215. **********************************************************/
  216. wide *WideAssign32
  217. (
  218.     wide    *target_ptr,    /* out: 64 bits to be assigned */
  219.     long     value            /* in:  assignment value */
  220. )
  221. {
  222.     /* initialize Wide library if not already done */
  223.     if( !gWide_Initialized ) WideInit();
  224.  
  225.     target_ptr->lo = value;
  226.     target_ptr->hi = (value >= 0) ? 0: -1;
  227.  
  228.     return( target_ptr );
  229. }
  230.  
  231.  
  232.  
  233. /**********************************************************
  234.  
  235.     WideAdd32 - Add 32 bits to a 64 bit int
  236.  
  237.     Description:
  238.         This routine will add a signed 32 bit integer to
  239.         a signed 64 bit integer
  240.  
  241.     Return value:
  242.         the target pointer passed into this function
  243.  
  244. **********************************************************/
  245. wide *WideAdd32
  246. (
  247.     wide    *target_ptr,    /* out: 64 bits to be added to */
  248.     long     value          /* in:  addition value */
  249. )
  250. {
  251.     wide    temp;
  252.  
  253.  
  254.     /* note: library initialization check done by WideAdd() */
  255.  
  256.     /* convert value to 64 bits */
  257.     temp.lo = value;
  258.     temp.hi = (value >= 0) ? 0: -1;
  259.  
  260.     /* do the add */
  261.     return( (wide *)WideAdd( target_ptr, &temp ) );
  262. }
  263.  
  264.  
  265.  
  266. /**********************************************************
  267.  
  268.     WideSubtract32 - Subtract 32 bits from a 64 bit int
  269.  
  270.     Description:
  271.         This routine will subtract a signed 32 bit integer from
  272.         a signed 64 bit integer
  273.  
  274.     Return value:
  275.         the target pointer passed into this function
  276.  
  277. **********************************************************/
  278. wide *WideSubtract32
  279. (
  280.     wide    *target_ptr,    /* out: 64 bits to be subtracted from */
  281.     long     value          /* in:  subtraction value */
  282. )
  283. {
  284.     wide    temp;
  285.  
  286.  
  287.     /* note: library initialization check done by WideSubtract() */
  288.  
  289.     /* convert value to 64 bits */
  290.     temp.lo = value;
  291.     temp.hi = (value >= 0) ? 0: -1;
  292.  
  293.     /* do the subtract */
  294.     return( (wide *)WideSubtract( target_ptr, &temp ) );
  295. }
  296.  
  297.  
  298.  
  299. /* IF QuickDraw GX is not included */
  300. #ifndef __GXMATH__
  301.  
  302. /**********************************************************
  303.  
  304.     WideScale - (gx) Highest order nonzero bit in a 64 bit number
  305.  
  306.     Description:
  307.         This routine will return the bit number of the
  308.         highest-order nonzero bit in a 64 bit number.
  309.  
  310.     Return value:
  311.         0 to 63 (bit position of highest-order nonzero bit)
  312.         or
  313.         -1 if all bits are zero
  314.  
  315. **********************************************************/
  316. short WideScale
  317. (
  318.     const wide  *bigint_ptr     /* in: 64 bits to test */
  319. )
  320. {
  321. register short           rv;
  322. register long           accum_hi;
  323. register unsigned long accum_lo;
  324.  
  325.  
  326.     /* initialize Wide library if not already done */
  327.     if( !gWide_Initialized ) WideInit();
  328.  
  329.     rv = 63;
  330.     accum_hi = bigint_ptr->hi;
  331.     accum_lo = bigint_ptr->lo;
  332.  
  333.     /* WHILE we have not found the left-most 1 bit */
  334.     while( ((accum_hi & LONG_SIGN_BIT) == 0) && (rv >= 0) )
  335.     {
  336.         --rv;
  337.  
  338.         /* shift 64 bits left once */
  339.         accum_hi <<= 1;
  340.         if( accum_lo & LONG_SIGN_BIT )
  341.         {
  342.             accum_hi |= 1;
  343.         }
  344.         accum_lo <<= 1;
  345.     }
  346.  
  347.     return( rv );
  348. }
  349. #endif
  350.  
  351.  
  352.  
  353. /**********************************************************
  354.  
  355.     Wide_ToExtended - internal 68K routine
  356.     Wide_ToDouble   - internal PPC routine
  357.  
  358.     Description:
  359.         An internal routine that converts a signed
  360.         'wide' value to a signed 'extended' or Double value.
  361.  
  362.     Return value:
  363.         none
  364.  
  365. **********************************************************/
  366.  
  367. /* IF generating code for 680x0 CPUs */
  368. #if GENERATING68K
  369. static void Wide_ToExtended
  370. (
  371.     Extended_80 *target_ptr,    /* out: extended number */
  372.     const  wide *source_ptr     /* in:  64 bits to convert */
  373. )
  374. {
  375.     short    sign_bit;
  376.     short    left_most;
  377.     wide    work_int = *source_ptr;
  378.     struct _extended80 *outp = (struct _extended80 *) target_ptr;
  379.  
  380.  
  381.     /* IF negative */
  382.     sign_bit = (work_int.hi & LONG_SIGN_BIT) >> 16;
  383.     if( sign_bit )
  384.     {
  385.         /* convert number to positive */
  386.         WideNegate( &work_int );
  387.     }
  388.  
  389.     /* determine left-most 1 bit */
  390.     left_most = WideScale( &work_int );
  391.  
  392.     /* IF there are no 1 bits */
  393.     if( left_most < 0 )
  394.     {
  395.         /* the answer is zero */
  396.         outp->exp = 0;
  397.         outp->man[0] = 0;
  398.         outp->man[1] = 0;
  399.         outp->man[2] = 0;
  400.         outp->man[3] = 0;
  401.     }
  402.     /* ELSE a non-zero number */
  403.     else
  404.     {
  405.         /* left justify the bits */
  406.         WideBitShift( &work_int, -(63 - left_most) );
  407.  
  408.         /* output the 'extended' number */
  409.         outp->exp = sign_bit | (0x3FFF + left_most);
  410.         (*(long *) &outp->man[0]) = work_int.hi;
  411.         (*(long *) &outp->man[2]) = work_int.lo;
  412.     }
  413. }
  414.  
  415. /* ELSE generating code for PowerPC */
  416. #else
  417. static void Wide_ToDouble
  418. (
  419.     double_t    *target_ptr,    /* out: double number */
  420.     const  wide *source_ptr     /* in:  64 bits to convert */
  421. )
  422. {
  423.     long            left_most;
  424.     unsigned long    sign_bit;
  425.     wide    work_int = *source_ptr;
  426.     union
  427.     {
  428.         double_t        dbl_num;
  429.         unsigned long    half[2];
  430.     } work;
  431.  
  432.  
  433.     /* IF negative */
  434.     sign_bit = work_int.hi & LONG_SIGN_BIT;
  435.     if( sign_bit )
  436.     {
  437.         /* convert number to positive */
  438.         WideNegate( &work_int );
  439.     }
  440.  
  441.     /* determine left-most 1 bit */
  442.     left_most = WideScale( &work_int );
  443.  
  444.     /* IF there are no 1 bits */
  445.     if( left_most < 0 )
  446.     {
  447.         /* build the double number */
  448.         work.half[0] = 0;
  449.         work.half[1] = 0;
  450.     }
  451.     /* ELSE a non-zero number */
  452.     else
  453.     {
  454.         /* left justify the bits and toss the msb (so we normalize the fraction) */
  455.         WideBitShift( &work_int, -(64 - left_most) );
  456.  
  457.         /* build the double number */
  458.         work.half[0] = sign_bit | ((0x3FF + left_most) << 20);
  459.         work.half[0] |= (work_int.hi >> 12) & 0x000FFFFF;
  460.         work.half[1] = (work_int.hi << 20) | ((work_int.lo >> 12) & 0x000FFFFF);
  461.     }
  462.  
  463.     /* output the result */
  464.     *target_ptr = work.dbl_num;
  465. }
  466. #endif
  467.  
  468.  
  469.  
  470. /**********************************************************
  471.  
  472.     WideToDecStr - Convert 64 bit int to a SANE 'decimal' string
  473.  
  474.     Description:
  475.         This routine will convert a signed 64 bit integer
  476.         to the 'decimal' type string supported by the SANE library.
  477.  
  478.     Return value:
  479.         none
  480.  
  481. **********************************************************/
  482. void WideToDecStr
  483. (
  484.           decimal   *decstr_ptr,    /* out: 'decimal' output string */
  485.     const wide        *source_ptr     /* in:  64 bits to convert */
  486. )
  487. /* IF generating code for 680x0 CPUs */
  488. #if GENERATING68K
  489. {
  490.     decform         format;
  491.     Extended_80     ext_number;
  492.  
  493.  
  494.     /* initialize Wide library if not already done */
  495.     if( !gWide_Initialized ) WideInit();
  496.  
  497.     /* convert 'wide' number to 'extended' format */
  498.     Wide_ToExtended( &ext_number, source_ptr );
  499.  
  500.     /* define how num2dec() will generate the string */
  501.     format.style = FIXEDDECIMAL;
  502.     format.digits = 0;
  503.  
  504.     /* pre-initialize to zero because for Symantec SANE (possibly   */
  505.     /* others) decimal.exp will be uninitialized if ext_number is 0 */
  506.     decstr_ptr->exp = 0;
  507.  
  508.     /* IF 68K MetroWorks compiler, the second parameter of num2dec()
  509.        is a pointer instead of a value as defined in PowerPC Numerics */
  510. #ifdef __MWERKS__
  511.     /* generate the 'decimal' string */
  512.     Num2Dec( &format, &ext_number, decstr_ptr );
  513. #else
  514.     /* generate the 'decimal' string */
  515.     num2dec( &format, ext_number, decstr_ptr );
  516. #endif
  517. }
  518. /* ELSE generating code for PowerPC */
  519. #else
  520. {
  521.     decform     format;
  522.     double_t    dbl_number;
  523.  
  524.  
  525.     /* initialize Wide library if not already done */
  526.     if( !gWide_Initialized ) WideInit();
  527.  
  528.     /* convert 'wide' number to 'double' format */
  529.     Wide_ToDouble( &dbl_number, source_ptr );
  530.  
  531.     format.style = FIXEDDECIMAL;
  532.     format.digits = 0;
  533.  
  534.     /* generate the 'decimal' string */
  535.     num2dec( &format, dbl_number, decstr_ptr );
  536. }
  537. #endif
  538.  
  539.  
  540.  
  541. /* IF generating code for 680x0 CPUs */
  542. #if GENERATING68K
  543.  
  544. /**********************************************************
  545.  
  546.     WideBitShift - Shift a 64 bit number
  547.  
  548.     Description:
  549.         This routine will perform an arithmetic shift on a
  550.         64 bit number.
  551.  
  552.         If the shift amount is 0, then the resulting value
  553.         will be the same as the input value.
  554.  
  555.         When the shift amount is positive, the 64 bit number
  556.         will be shifted to the right (decreasing magnitude). 
  557.  
  558.         When the shift amount is negative, the 64 bit number
  559.         will be shifted to the left (decreasing increasing). 
  560.  
  561.     Return value:
  562.         the target pointer passed into this function
  563.  
  564. **********************************************************/
  565. wide *WideBitShift
  566. (
  567.     wide    *target_ptr,    /* in/out: 64 bits to be shifted */
  568.     short       amount      /* in:     shift amount (+ right, - left) */
  569. )
  570. {
  571. register long hi;
  572. register unsigned long lo;
  573. register short shift_amount;
  574.  
  575.  
  576.     /* initialize Wide library if not already done */
  577.     if( !gWide_Initialized ) WideInit();
  578.  
  579.     hi = target_ptr->hi;
  580.     lo = target_ptr->lo;
  581.     shift_amount = amount;
  582.  
  583.     /* IF shifting right more than 31 bits */
  584.     if( shift_amount > 31 )
  585.     {
  586.         lo = hi >> (shift_amount - 32);
  587.         hi = 0;
  588.     }
  589.     /* ELSE IF shifting right 1-31 bits */
  590.     else if( shift_amount > 0 )
  591.     {
  592.         lo = (lo >> shift_amount) | (hi << (32 - shift_amount));
  593.         hi >>= shift_amount;
  594.     }
  595.     /* ELSE IF shifting left more than 31 bits */
  596.     else if( shift_amount < -31 )
  597.     {
  598.         hi = lo << -(shift_amount + 32);
  599.         lo = 0;
  600.     }
  601.     /* ELSE IF shifting left 1-31 bits */
  602.     else if( shift_amount < 0 )
  603.     {
  604.         hi = (hi << -shift_amount) | (lo >> (32 + shift_amount));
  605.         lo <<= -shift_amount;
  606.     }
  607.  
  608.     target_ptr->hi = hi;
  609.     target_ptr->lo = lo;
  610.  
  611.     return( target_ptr );
  612. }
  613.  
  614.  
  615.  
  616. /* IF QuickDraw GX is not included */
  617. #ifndef __GXMATH__
  618.  
  619.  
  620. /**********************************************************
  621.  
  622.     WideAdd - (gx) Add two 64 bit ints
  623.  
  624.     Description:
  625.         This routine will add a signed 64 bit integer to
  626.         a signed 64 bit integer.
  627.  
  628.         The source integer will be added to the target integer.
  629.  
  630.     Return value:
  631.         the target pointer passed into this function
  632.  
  633. **********************************************************/
  634. wide *WideAdd
  635. (
  636.           wide  *target_ptr,    /* out: 64 bits to be added to */
  637.     const wide  *source_ptr        /* in:  addition value */
  638. )
  639. {
  640. register unsigned long accum_lo;
  641. register long           accum_hi;
  642. register wide *destp;
  643.  
  644.  
  645.     /* initialize Wide library if not already done */
  646.     if( !gWide_Initialized ) WideInit();
  647.  
  648.     /* perform a partial add */
  649.     destp = target_ptr;
  650.     accum_lo = destp->lo + source_ptr->lo;
  651.     accum_hi = destp->hi + source_ptr->hi;
  652.  
  653.     /* IF the low long has overflowed */
  654.     if( (accum_lo < destp->lo) ||
  655.         (accum_lo < source_ptr->lo) )
  656.     {
  657.         /* propagate the carry */
  658.         accum_hi += 1;
  659.     }
  660.  
  661.     destp->hi = accum_hi;
  662.     destp->lo = accum_lo;
  663.  
  664.     return( destp );
  665. }
  666.  
  667.  
  668.  
  669.  
  670. /**********************************************************
  671.  
  672.     WideCompare - (gx) Compare two 64 bits ints
  673.  
  674.     Description:
  675.         This routine will compare a signed 64 bit integer
  676.         with a signed 64 bit integer.
  677.  
  678.     Return value:
  679.         1  if target number is greater than the source number
  680.         0  if the two numbers are equal
  681.        -1  if target is less than the source number
  682.         
  683. **********************************************************/
  684. short WideCompare
  685. (
  686.     const wide    *target_ptr,    /* in: target number */
  687.     const wide    *source_ptr     /* in: source number */
  688. )
  689. {
  690.     wide  work;
  691.  
  692.  
  693.     /* note: library initialization check done by WideSubtract() */
  694.  
  695.     work = *target_ptr;
  696.     WideSubtract( &work, source_ptr );
  697.  
  698.     if( (work.hi == 0) && (work.lo == 0) )
  699.     {
  700.         return( 0 );
  701.     }
  702.  
  703.     if( work.hi < 0 )
  704.     {
  705.         return( -1 );
  706.     }
  707.  
  708.     return( 1 );
  709. }
  710.  
  711.  
  712.  
  713. /**********************************************************
  714.  
  715.     Wide_DivideU - internal routine
  716.  
  717.     Description:
  718.         A 680x0 assembly language routine that performs an
  719.         performs an unsigned 64 bit division.
  720.  
  721.         The algorithm is a binary version of the paper and
  722.         pencil method of division you learned in school.
  723.         It will loop once for each bit in the sizeof the
  724.         divisor (which is 32).
  725.  
  726.     Return value:
  727.         none
  728.  
  729. **********************************************************/
  730. #if defined(MPWC)
  731. extern void Wide_DivideU
  732. (
  733.     wide    *dividend_ptr,        /* in/out:  64 bits to be divided */
  734.     long     divisor,            /* in:      value to divide by */
  735.     long    *remainder_ptr        /* out:     the remainder of the division */
  736. );
  737. #else
  738. ASM_FUNC_HEAD static void Wide_DivideU
  739. (
  740.     wide    *dividend_ptr,        /* in/out:  64 bits to be divided */
  741.     long     divisor,            /* in:      value to divide by */
  742.     long    *remainder_ptr        /* out:     the remainder of the division */
  743. )
  744. {
  745. #define DIVIDEND_PTR   8
  746. #define DIVISOR       12
  747. #define REMAINDER_PTR 16
  748.  
  749. ASM_BEGIN
  750.         MOVEM.L D2-D7,-(SP)            // save work registers
  751.         CLR.L    D0                    //
  752.         CLR.L    D1                    // D0-D1 is the quotient accumulator
  753.         MOVE.L    DIVIDEND_PTR(A6),A0    //
  754.         MOVE.L    WIDE_HI(A0),D2      //
  755.         MOVE.L    WIDE_LO(A0),D3      // D2-D3 is the remainder accumulator
  756.         CLR.L    D4                    //
  757.         MOVE.L    D2,D5                // D5 = copy of dividend.hi
  758.         MOVE.L    DIVISOR(A6),D6        // D6 = copy of divisor
  759.  
  760.         MOVEQ.L #31,D7                // FOR number of bits in divisor (see @div99:)
  761. @divloop:
  762.         LSL.L   #1,D0               // shift quotient.hi accumulator left once
  763.         LSL.L   #1,D1               // shift quotient.lo accumulator left once
  764.         LSL.L    #1,D4                //
  765.         LSL.L   #1,D3               // shift remainder accumulator left once
  766.         BCC        @div29                // IF CC, a zero bit shifted out
  767.         LSL.L   #1,D2               //
  768.         BSET    #0,D2                //
  769.         BRA        @div30
  770. @div29:
  771.         LSL.L   #1,D2               //
  772. @div30:
  773.         SUB.L    D6,D2                // remainder -= divisor
  774.         BCS        @div50                // IF CS, remainder is negative
  775.         BSET    #0,D1                // quotient.lo |= 1
  776.         BRA.S    @div77                //
  777. @div50:
  778.         ADD.L    D6,D2                // remainder += divisor
  779. @div77:
  780.         BTST    D7,D5                //
  781.         BEQ        @div90                // IF EQ, bit not set in dividend.hi
  782.         BSET    #0,D4                //
  783. @div90:
  784.         CMP.L    D6,D4                //
  785.         BCS        @div99                // IF CS, divisor < D4
  786.         SUB.L    D6,D4                // D4 -= divisor
  787.         BSET    #0,D0                // quotient.hi |= 1
  788. @div99:
  789.         DBF        D7,@divloop            // loop until D7 == -1
  790.  
  791.         MOVE.L    DIVIDEND_PTR(A6),A0 // output the remainder
  792.         MOVE.L    D0,WIDE_HI(A0)      //
  793.         MOVE.L    D1,WIDE_LO(A0)      //
  794.         MOVE.L    REMAINDER_PTR(A6),A0// output the remainder
  795.         MOVE.L    D2,(A0)             //
  796.         MOVEM.L (SP)+,D2-D7            // restore work registers
  797. ASM_END
  798. ASM_FUNC_TAIL
  799. }
  800. #endif
  801.  
  802.  
  803. /**********************************************************
  804.  
  805.     Wide_DivideS - internal routine
  806.  
  807.     Description:
  808.         An internal routine that will divide a signed 32 bit
  809.         number into a signed 64 bit number and produce a
  810.         signed 64 bit result.
  811.  
  812.     Return value:
  813.         none
  814.  
  815. **********************************************************/
  816. static void Wide_DivideS
  817. (
  818.     wide    *dividend_ptr,        /* in/out:  64 bits to be divided */
  819.     long     divisor,            /* in:      value to divide by */
  820.     long    *remainder_ptr        /* out:     the remainder of the division */
  821. )
  822. {
  823.     wide    dividend;
  824.     long    remainder;
  825.     long    negative_result;
  826.  
  827.  
  828.     dividend = *dividend_ptr;
  829.     
  830.     /* determine if result of the divide will be positive or negative */
  831.     negative_result = (dividend_ptr->hi & LONG_SIGN_BIT) ^ (divisor & LONG_SIGN_BIT);
  832.  
  833.     /* IF dividend is negative */
  834.     if( dividend_ptr->hi < 0 )
  835.     {
  836.         /* divide algorithm is unsigned */
  837.         WideNegate( ÷nd );;
  838.     }
  839.  
  840.     /* IF divisor is negative */
  841.     if( divisor < 0 )
  842.     {
  843.         /* divide algorithm is unsigned */
  844.         divisor = -divisor;
  845.     }
  846.  
  847.     /* perform an unsigned division */
  848.     Wide_DivideU( ÷nd, divisor, &remainder );
  849.  
  850.     /* IF negative dividend */
  851.     if( dividend_ptr->hi < 0 )
  852.     {
  853.         *remainder_ptr = -remainder;
  854.     }
  855.     else
  856.     {
  857.         *remainder_ptr = remainder;
  858.     }
  859.  
  860.     /* IF negative quotient */
  861.     if( negative_result )
  862.     {
  863.         /* correct the sign */
  864.         WideNegate( ÷nd );
  865.     }
  866.  
  867.     *dividend_ptr = dividend;
  868. }
  869.  
  870.  
  871.  
  872.  
  873. /**********************************************************
  874.  
  875.     WideWideDivide - (gx) Divide 32 bit int into 64 bit int with a 64 bit result
  876.  
  877.     Description:
  878.         This routine will divide a signed 32 bit integer into
  879.         a signed 64 bit integer and return a signed 64 bit quotient
  880.         and a 32 bit remainder.
  881.  
  882.         When this function returns the dividend will be replaced
  883.         by the quotient
  884.  
  885.         If the divisor is zero, then the quotient will be set to the
  886.         largest positive or negative number, as appropriate.
  887.         And the remainder will be gxNegativeInfinity.
  888.  
  889.         If the 'remainder_ptr' parameter is NULL or (long *)-1
  890.         then no remainder will be returned.
  891.  
  892.     Return value:
  893.         pointer to the quotient
  894.  
  895. **********************************************************/
  896. wide *WideWideDivide
  897. (
  898.     wide    *dividend_ptr,        /* in/out:  64 bits to be divided */
  899.     long     divisor,            /* in:      value to divide by */
  900.     long    *remainder_ptr        /* out:     the remainder of the division */
  901. )
  902. {
  903.     long    remainder;
  904.  
  905.  
  906.     /* initialize Wide library if not already done */
  907.     if( !gWide_Initialized ) WideInit();
  908.  
  909.     /* IF dividing by zero */
  910.     if( divisor == 0 )
  911.     {
  912.         remainder = gxNegativeInfinity;
  913.  
  914.         /* IF dividend is negative */
  915.         if( (dividend_ptr->hi < 0) )
  916.         {
  917.             dividend_ptr->hi = gxNegativeInfinity;
  918.             dividend_ptr->lo = 0;
  919.         }
  920.         /* ELSE dividend is positive */
  921.         else
  922.         {
  923.             dividend_ptr->hi = gxPositiveInfinity;
  924.             dividend_ptr->lo = ~0;
  925.         }
  926.     }
  927.     /* ELSE overflow is not possible */
  928.     else
  929.     {
  930.         /* do the divide */
  931.         Wide_DivideS( dividend_ptr, divisor, &remainder );
  932.     }
  933.  
  934.  
  935.     /* IF the user wants a remainder */
  936.     if( (remainder_ptr != NULL) &&
  937.         (remainder_ptr != (long *) -1) )
  938.     {
  939.         *remainder_ptr = remainder;
  940.     }
  941.  
  942.     return( dividend_ptr );
  943. }
  944.  
  945.  
  946.  
  947. /**********************************************************
  948.  
  949.     Wide_DivS64 - internal routine
  950.  
  951.     Description:
  952.         A 680x0 assembly language routine that performs a
  953.         signed 64 bit division by using the DIVS.L instruction.
  954.  
  955.         The 64 bit DIVS.L instruction is only available on the
  956.         68020 to 68040 processors.
  957.  
  958.     Return value:
  959.         32 bit quotient
  960.  
  961. **********************************************************/
  962. #if defined(MPWC)
  963. extern long Wide_DivS64
  964. (
  965.     const wide    *dividend_ptr,        /* in/out:  64 bits to be divided */
  966.     long         divisor,            /* in:      value to divide by */
  967.     long        *remainder_ptr,        /* out:     the remainder of the division */
  968.     short        *overflow_ptr        /* out:     flag indicating if overflow occured */
  969. );
  970. #else
  971. ASM_FUNC_HEAD static long Wide_DivS64
  972. (
  973.     const wide    *dividend_ptr,        /* in/out:  64 bits to be divided */
  974.     long         divisor,            /* in:      value to divide by */
  975.     long        *remainder_ptr,        /* out:     the remainder of the division */
  976.     short        *overflow_ptr        /* out:     flag indicating if overflow occured */
  977. )
  978. {
  979. #define DIVIDEND_PTR   8
  980. #define DIVISOR       12
  981. #define REMAINDER_PTR 16
  982. #define OVERFLOW_PTR  20
  983.  
  984. ASM_BEGIN
  985.         MOVE.L  D2,-(SP)
  986.         MOVEQ.L    #1,D2                    // assume there is overflow
  987.         MOVE.L  DIVIDEND_PTR(A6),A0     // A0 -> the dividend
  988.         MOVE.L    WIDE_LO(A0),D0            //
  989.         MOVE.L    WIDE_HI(A0),D1            // D1-D0 = 64 bit dividend
  990.         DC.W    0x4C6E,0x0C01,0x000C    // DIVS.L divisor(A6),D1-D0  (64bit signed divide)
  991.         BVS        @divcont                // IF VS, we're overflowed
  992.         CLR.W    D2                        // ELSE, clear the overflow flag
  993. @divcont:
  994.         MOVE.L    REMAINDER_PTR(A6),A0    // output remainder
  995.         MOVE.L    D1,(A0)                    //
  996.         MOVE.L    OVERFLOW_PTR(A6),A0        // output overflow flag
  997.         MOVE.W    D2,(A0)                    //
  998.         MOVE.L  (SP)+,D2
  999. ASM_END
  1000. ASM_FUNC_TAIL
  1001. }
  1002. #endif
  1003.  
  1004.  
  1005. /**********************************************************
  1006.  
  1007.     WideDivide - (gx) Divide 32 bit int into 64 bit int with a 32 bit result
  1008.  
  1009.     Description:
  1010.         This routine will divide a signed 32 bit integer into
  1011.         a signed 64 bit integer and return a signed 32 bit quotient
  1012.         and a 32 bit remainder.
  1013.  
  1014.         Since the return value is a 32 bit integer, overflow is possible.
  1015.         If a positive overflow occurs, the return value will be gxPositiveInfinity
  1016.         If a negative overflow occurs, the return value will be gxNegativeInfinity
  1017.         In both cases *remainder_ptr will be set to gxNegativeInfinity.
  1018.  
  1019.         If a NULL pointer is passed for the 'remainder_ptr' parameter
  1020.         then no remainder will be returned.
  1021.  
  1022.         If the pointer passed to 'remainder_ptr' is (long *)-1
  1023.         then no remainder will be returned but in the case of an
  1024.         overflow gxNegativeInfinity will be the return value.
  1025.  
  1026.     Return value:
  1027.         quotient (the integer result of the division)
  1028.         or
  1029.         gxNegativeInfinity if negative overflow
  1030.         or
  1031.         gxPositiveInfinity if positive overflow
  1032.  
  1033. **********************************************************/
  1034. long WideDivide
  1035. (
  1036.     const wide *dividend_ptr,    /* in:  64 bits to be divided */
  1037.     long        divisor,        /* in:  value to divide by */
  1038.     long       *remainder_ptr    /* out: the remainder of the division */
  1039. )
  1040. {
  1041.     long    rv;
  1042.     long    remainder;
  1043.     wide    work;
  1044.     short    overflow;
  1045.  
  1046.  
  1047.     /* initialize Wide library if not already done */
  1048.     if( !gWide_Initialized ) WideInit();
  1049.  
  1050.     /* IF not dividing by zero */
  1051.     if( divisor != 0 )
  1052.     {
  1053.         /* IF the 68k 64bit divide instruction is not available */
  1054.         if( !gWide_64instr )
  1055.         {
  1056.             /* use a software subroutine for the division */
  1057.             work = *dividend_ptr;
  1058.             Wide_DivideS( &work, divisor, &remainder );
  1059.             rv = work.lo;
  1060.  
  1061.             /* determine if result overflowed a long */
  1062.             overflow = (work.hi != 0) && (work.hi != -1);
  1063.         }
  1064.         /* ELSE the 64bit division instruction is available */
  1065.         else
  1066.         {
  1067.             /* use an assembly language instruction to do the division */
  1068.             rv = Wide_DivS64( dividend_ptr, divisor, &remainder, &overflow );
  1069.         }
  1070.  
  1071.  
  1072.         /* IF the user wants a remainder */
  1073.         if( (remainder_ptr != NULL) &&
  1074.             (remainder_ptr != (long *) -1) )
  1075.         {
  1076.             *remainder_ptr = remainder;
  1077.         }
  1078.     }
  1079.  
  1080.  
  1081.     /* IF there was an overflow */
  1082.     if( overflow )
  1083.     {
  1084.         /* IF user wants a single overflow indication in the return value */
  1085.         if( remainder_ptr == (long *) -1 )
  1086.         {
  1087.             rv = gxNegativeInfinity;
  1088.         }
  1089.         else
  1090.         {
  1091.             /* IF there is a remainder pointer */
  1092.             if( remainder_ptr != NULL )
  1093.             {
  1094.                 *remainder_ptr = gxNegativeInfinity;
  1095.             }
  1096.  
  1097.             /* set overflow return value based on sign of the result */
  1098.             if( (dividend_ptr->hi & LONG_SIGN_BIT) ^ (divisor & LONG_SIGN_BIT) )
  1099.             {
  1100.                 rv = gxNegativeInfinity;
  1101.             }
  1102.             else
  1103.             {
  1104.                 rv = gxPositiveInfinity;
  1105.             }
  1106.         }
  1107.     }
  1108.  
  1109.     return( rv );
  1110. }
  1111.  
  1112.  
  1113.  
  1114. /**********************************************************
  1115.  
  1116.     Wide_MulS64 - internal routine
  1117.  
  1118.     Description:
  1119.         A 680x0 assembly language routine that performs a
  1120.         signed 64 bit division by using the MULS.L instruction.
  1121.  
  1122.         The 64 bit MULS.L instruction is only available on the
  1123.         68020 to 68040 processors.
  1124.  
  1125.     Return value:
  1126.         none
  1127.  
  1128. **********************************************************/
  1129. #if defined(MPWC)
  1130. extern void Wide_MulS64
  1131. (
  1132.     long    multiplicand,        /* in:  first value to multiply */
  1133.     long    multiplier,            /* in:  second value to multiply */
  1134.     wide   *out_ptr                /* out: 64 bits to be assigned */
  1135. );
  1136. #else
  1137. ASM_FUNC_HEAD static void Wide_MulS64
  1138. (
  1139.     long    multiplicand,        /* in:  first value to multiply */
  1140.     long    multiplier,            /* in:  second value to multiply */
  1141.     wide   *out_ptr                /* out: 64 bits to be assigned */
  1142. )
  1143. {
  1144. #define MULTIPLICAND   8
  1145. #define MULTIPLIER    12
  1146. #define OUT_PTR       16
  1147.  
  1148. ASM_BEGIN
  1149.         MOVE.L  MULTIPLICAND(A6),D0     //
  1150.         DC.W    0x4C2E,0x0C01,0x000C    // MULS.L multiplier(A6),D1-D0; 64bit signed multiply
  1151.         MOVE.L  OUT_PTR(A6),A0          //
  1152.         MOVE.L  D0,WIDE_LO(A0)          // WIDE_LO defined earlier
  1153.         MOVE.L  D1,WIDE_HI(A0)          // WIDE_HI defined earlier
  1154. ASM_END
  1155. ASM_FUNC_TAIL
  1156. }
  1157. #endif
  1158.  
  1159.  
  1160. /**********************************************************
  1161.  
  1162.     WideMultiply - (gx) Multiply two 32 bits ints for a 64 bit result
  1163.  
  1164.     Description:
  1165.         This routine will multiply two signed 32 bit values
  1166.         and assign the result to a signed 64 bit integer
  1167.  
  1168.     Return value:
  1169.         the target pointer passed into this function
  1170.  
  1171. **********************************************************/
  1172. wide *WideMultiply
  1173. (
  1174.     long    multiplicand,        /* in:  first value to multiply */
  1175.     long    multiplier,            /* in:  second value to multiply */
  1176.     wide   *target_ptr            /* out: 64 bits to be assigned */
  1177. )
  1178. {
  1179.     /* initialize Wide library if not already done */
  1180.     if( !gWide_Initialized ) WideInit();
  1181.  
  1182.     /* IF the 64bit multiply instruction is available */
  1183.     if( gWide_64instr )
  1184.     {
  1185.         /* execute the assembly language instruction MULS.L */
  1186.         Wide_MulS64( multiplicand, multiplier, target_ptr );
  1187.     }
  1188.     else
  1189.     {
  1190.         /* call toolbox to perform the multiply */
  1191.         LongMul( multiplicand, multiplier, (Int64Bit *) target_ptr );
  1192.     }
  1193.  
  1194.     return( target_ptr );
  1195. }
  1196.  
  1197.  
  1198.  
  1199.  
  1200. /**********************************************************
  1201.  
  1202.     WideNegate - (gx) Negative value of a 64 bit int
  1203.  
  1204.     Description:
  1205.         This routine will calculate the negative value of
  1206.         a signed 64 bit integer
  1207.  
  1208.     Return value:
  1209.         the target pointer passed into this function
  1210.  
  1211. **********************************************************/
  1212. wide *WideNegate
  1213. (
  1214.     wide    *target_ptr     /* in/out: 64 bits to be negated */
  1215. )
  1216. {
  1217. register long           accum_hi;
  1218. register unsigned long accum_lo;
  1219. register wide *destp;
  1220.  
  1221.  
  1222.     /* initialize Wide library if not already done */
  1223.     if( !gWide_Initialized ) WideInit();
  1224.  
  1225.     destp = target_ptr;
  1226.     accum_lo = destp->lo;
  1227.     accum_hi = destp->hi;
  1228.  
  1229.     /* 1's complement */
  1230.     accum_lo = ~accum_lo;
  1231.     accum_hi = ~accum_hi;
  1232.  
  1233.     /* 2's complement */
  1234.     accum_lo += 1;
  1235.     if( accum_lo == 0 )
  1236.     {
  1237.         /* propagate the carry */
  1238.         accum_hi += 1;
  1239.     }
  1240.  
  1241.     destp->hi = accum_hi;
  1242.     destp->lo = accum_lo;
  1243.  
  1244.     return( destp );
  1245. }
  1246.  
  1247.  
  1248.  
  1249.  
  1250. /**********************************************************
  1251.  
  1252.     WideShift() - (gx) Shift a 64 bit number and round up
  1253.  
  1254.     Description:
  1255.         This routine will perform an arithmetic shift on a
  1256.         64 bit number with rounding.
  1257.  
  1258.         The shift is be similar to the WideBitShift() routine
  1259.         except that the result is rounded by adding half and
  1260.         truncating the remainder.
  1261.  
  1262.         (eg) Performing a shift of +3 on a value of 0x0C will
  1263.              return 2 with WideShift() and 1 with WideBitShift()
  1264.  
  1265.     Return value:
  1266.         the target pointer passed into this function
  1267.  
  1268. **********************************************************/
  1269. wide *WideShift
  1270. (
  1271.     wide    *target_ptr,    /* in/out: 64 bits to be shifted */
  1272.     short       amount      /* in:     shift amount (+ right, - left) */
  1273. )
  1274. {
  1275.     long    shifted_out;
  1276.  
  1277.  
  1278.     /* initialize Wide library if not already done */
  1279.     if( !gWide_Initialized ) WideInit();
  1280.  
  1281.     /* IF shifting to the left */
  1282.     if( amount <= 0 )
  1283.     {
  1284.         /* perform an arithmetic shift */
  1285.         WideBitShift( target_ptr, amount );
  1286.     }
  1287.     /* ELSE shifting to the right */
  1288.     else
  1289.     {
  1290.         /* IF bit shifted out is in .lo */
  1291.         if( amount <= 32 )
  1292.         {
  1293.             shifted_out = target_ptr->lo & (1L << (amount-1));
  1294.         }
  1295.         /* ELSE IF bit shifted out is in .hi */
  1296.         else if( amount <= 64 )
  1297.         {
  1298.             shifted_out = target_ptr->hi & (1L << (amount-33));
  1299.         }
  1300.         else
  1301.         {
  1302.             shifted_out = 0;
  1303.         }
  1304.     
  1305.         /* perform an arithmetic shift */
  1306.         WideBitShift( target_ptr, amount );
  1307.     
  1308.         /* IF there was a bit shifted out */
  1309.         if( shifted_out != 0 )
  1310.         {
  1311.             /* add the bit that was shifted out */
  1312.             WideAdd32( target_ptr, 1 );
  1313.         }
  1314.     }
  1315.  
  1316.     return( target_ptr );
  1317. }
  1318.  
  1319.  
  1320.  
  1321. /**********************************************************
  1322.  
  1323.     Wide_FromExtended - internal routine
  1324.  
  1325.     Description:
  1326.         An internal routine that converts an unsigned 'extended'
  1327.         value to an unsigned 'wide' value.
  1328.  
  1329.     Return value:
  1330.         none
  1331.  
  1332. **********************************************************/
  1333. static void Wide_FromExtended
  1334. (
  1335.         wide        *target_ptr,    /* out: unsigned 64 bits */
  1336.   const Extended_80    *source_ptr     /* in:  unsigned extended number to convert */
  1337. )
  1338. {
  1339. register short           shift;
  1340. register unsigned long hi;
  1341. register unsigned long lo;
  1342. const struct _extended80 *inp = (struct _extended80 *) source_ptr;
  1343.  
  1344.  
  1345.     /* IF bits should be right justified */
  1346.     shift =  63 - (inp->exp - 0x3FFF);
  1347.     if( (shift > 0) && (shift < 64) )
  1348.     {
  1349.         /* get copy of 'extended' number */
  1350.         hi = (*(long *) &inp->man[0]);
  1351.         lo = (*(long *) &inp->man[2]);
  1352.  
  1353.         /* perform a logical shift to the right */
  1354.         while( shift-- > 0 )
  1355.         {
  1356.             lo >>= 1;
  1357.             if( hi & 1 )
  1358.                 lo |= LONG_SIGN_BIT;
  1359.             hi >>= 1;
  1360.         }
  1361.     }
  1362.     else
  1363.     {
  1364.         hi = 0;
  1365.         lo = 0;
  1366.     }
  1367.  
  1368.     /* output the result */
  1369.     target_ptr->hi = hi;
  1370.     target_ptr->lo = lo;
  1371. }
  1372.  
  1373.  
  1374.  
  1375. /**********************************************************
  1376.  
  1377.     WideSquareRoot - (gx) return 32 bit square root of an unsigned 64 bit number
  1378.  
  1379.     Description:
  1380.         This routine will calculate the unsigned 32 bit
  1381.         square root of an unsigned 64 bit number.
  1382.  
  1383.         Since the source number must be unsigned it's range
  1384.         can be from 0 to 2^64 - 1
  1385.  
  1386.         Overflow of the return value is not possible.
  1387.  
  1388.     Return value:
  1389.         32 bit unsigned square root
  1390.  
  1391. **********************************************************/
  1392. unsigned long WideSquareRoot
  1393. (
  1394.     const wide  *source_ptr        /* in: unsigned value to take the square root of */
  1395. )
  1396. {
  1397.     wide         work_int;
  1398.     Extended_80  ext_number;
  1399.  
  1400.  
  1401.     /* initialize Wide library if not already done */
  1402.     if( !gWide_Initialized ) WideInit();
  1403.  
  1404.     /* convert 'wide' number to 'extended' format */
  1405.     Wide_ToExtended( &ext_number, source_ptr );
  1406.  
  1407.     /* calculate the square root of a positive number using SANE */
  1408.  
  1409.     /* IF compiling with MetroWorks, the parameter of sqrt() is a
  1410.        pointer instead of a value as defined in PowerPC Numerics */
  1411. #ifdef __MWERKS__
  1412.     Sqrt( &ext_number );
  1413. #else
  1414.     ext_number = sqrt( ext_number );
  1415. #endif
  1416.  
  1417.     /* convert 'extended' format to 'wide' number */
  1418.     Wide_FromExtended( &work_int, &ext_number );
  1419.  
  1420.     /* ok to ignore work_int.hi because its always zero */
  1421.     return( work_int.lo );
  1422. }
  1423.  
  1424.  
  1425.  
  1426.  
  1427. /**********************************************************
  1428.  
  1429.     WideSubtract - (gx) Subtract a 64 bits int from a 64 bit int
  1430.  
  1431.     Description:
  1432.         This routine will subtract a signed 64 bit integer
  1433.         from a signed 64 bit integer
  1434.  
  1435.     Return value:
  1436.         the target pointer passed into this function
  1437.  
  1438. **********************************************************/
  1439. wide *WideSubtract
  1440. (
  1441.           wide  *target_ptr,    /* out: 64 bits to be subtracted from */
  1442.     const wide  *source_ptr        /* in:  subtraction value */
  1443. )
  1444. {
  1445. register unsigned long accum_lo;
  1446. register long           accum_hi;
  1447. register wide *destp;
  1448.  
  1449.  
  1450.     /* initialize Wide library if not already done */
  1451.     if( !gWide_Initialized ) WideInit();
  1452.  
  1453.     /* perform a partial subtract */
  1454.     destp = target_ptr;
  1455.     accum_lo = destp->lo - source_ptr->lo;
  1456.     accum_hi = destp->hi - source_ptr->hi;
  1457.  
  1458.     /* IF the low long has overflowed */
  1459.     if( destp->lo < source_ptr->lo )
  1460.     {
  1461.         /* propagate the borrow */
  1462.         accum_hi -= 1;
  1463.     }
  1464.  
  1465.     destp->hi = accum_hi;
  1466.     destp->lo = accum_lo;
  1467.  
  1468.     return( destp );
  1469. }
  1470.  
  1471. #endif
  1472.  
  1473. #endif